//
//  LoginViewController.swift
//  Link
//
//  Created by melvyn on 2018/8/21.
//  Copyright © 2018 NEET. All rights reserved.
//

import UIKit
import Alamofire
#if canImport(RxSwift)
import RxSwift
#endif

class LoginViewController: UIViewController {
    
    @IBOutlet weak var logo: UIImageView!
    @IBOutlet weak var avatar: UIImageView!
    @IBOutlet weak var circle: UIImageView!
    @IBOutlet weak var usernameField: UITextField!
    @IBOutlet weak var passwordField: UITextField!
    @IBOutlet weak var signinButton: UIButton!
    @IBOutlet weak var signupButton: UIButton!
    @IBOutlet weak var retrieveButton: UIButton!
    @IBOutlet weak var dismissButton: UIButton!
    
    @IBOutlet weak var bottomLayout: NSLayoutConstraint!
    @IBOutlet weak var containerBottomLayout: NSLayoutConstraint!
    @IBOutlet var stackViews: [UIStackView]!
    
    var completionHandler: ((Result<AuthSession>) -> Void)? = nil
    private var viewModel: LoginViewModel!
    #if canImport(RxSwift)
    private let disposeBag = DisposeBag()
    #else
    private var observation: NSObjectProtocol?
    
    deinit {
        unregisterForLocalNotification()
    }
    #endif
    
    convenience init() {
        let (nibName, bundle) = Assets.Nib.userLogin()
        self.init(nibName: nibName, bundle: bundle)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        avatar.layer.borderColor = UIColor.white.cgColor
        setupTextFields()
        registerForLocalNotification()
        updateAppearance(for: false)
        
        #if canImport(RxSwift)
        viewModel = LoginViewModel((
            usernameField.rx.text.asObservable().ignoreNil(),
            passwordField.rx.text.asObservable().ignoreNil()
        ))
        
        signinButton.rx.tap
            .bind(to: viewModel.attemptToLogin)
            .disposed(by: disposeBag)
        
        signupButton.rx.tap
            .flatMapLatest { [weak self] in Link.shared.rx.performRegistration(self) }
            .subscribe()
            .disposed(by: disposeBag)
        
        dismissButton.rx.tap
            .bind(onNext: { [unowned self] _ in
                self.presentingViewController?.dismiss(animated: true, completion: nil)
            })
            .disposed(by: disposeBag)
        
        viewModel.isLoginEnabled
            .drive(signinButton.rx.isEnabled)
            .disposed(by: disposeBag)
        
        viewModel.didLoggedIn
            .drive(onNext: { [weak self] result in
                
                guard result.isSuccess, result.value != nil else {
                    self?.completionHandler?(result)
                    return
                }
                
                self?.presentingViewController?.dismiss(animated: true, completion: {
                    self?.completionHandler?(result)
                })
            })
            .disposed(by: disposeBag)
        
        #else
        viewModel = LoginViewModel.init()
        
        signinButton.addEventHandler({ [weak self] in
            self?.viewModel.input = (usernameField.text ?? "", passwordField.text ?? "")
            self?.viewModel.signinEventHandler()
            }, for: .touchUpInside)
        
        signupButton.addEventHandler({ [weak self] in
            self?.present(RegisterViewController(), animated: true, completion: nil)
            }, for: .touchUpInside)
        
        dismissButton.addEventHandler({ [weak self] in
            self?.presentingViewController?.dismiss(animated: true, completion: nil)
            }, for: .touchUpInside)
        
        viewModel.didLoggedIn = { [weak self] result in
            guard result.isSuccess, result.value != nil else {
                self?.completionHandler?(result)
                return
            }
            
            self?.presentingViewController?.dismiss(animated: true, completion: {
                self?.completionHandler?(result)
            })
        }
        #endif
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        startAnimation()
    }
    
    private func setupTextFields() {
        usernameField.leftView = UIImageView(image: Assets.Image.username())
        usernameField.leftViewMode = .always
        
        passwordField.leftView = UIImageView(image: Assets.Image.password())
        passwordField.leftViewMode = .always
    }
    
    #if canImport(RxSwift)
    private func registerForLocalNotification() {
        NotificationCenter.default.rx.notification(UIResponder.keyboardWillChangeFrameNotification)
            .subscribe(onNext: { [weak self](note) in
                self?.note(note)
            })
            .disposed(by: disposeBag)
    }
    #else
    private func registerForLocalNotification() {
        observation = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification, object: nil, queue: nil, using: { [weak self](note) in
            self?.note(note)
        })
    }
    
    private func unregisterForLocalNotification() {
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }
    #endif
    
    private func note(_ note: Notification) {
        let beginFrame = note.userInfo![UIResponder.keyboardFrameBeginUserInfoKey] as! CGRect
        let endFrame = note.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
        let duration = note.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as! TimeInterval
        
        UIView.animate(withDuration: duration * 1.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
            let isEditing = beginFrame.origin.y > endFrame.origin.y
            
            self.updateAppearance(for: isEditing)
            self.bottomLayout.constant = isEditing ? self.view.bounds.height - endFrame.origin.y - 55 : 84
            self.view.layoutIfNeeded()
        }, completion: nil)
    }
    
    private func updateAppearance(for isEditing: Bool) {
        let attibutes: [NSAttributedString.Key : Any] = [
            .font : UIFont.systemFont(ofSize: 15),
            .foregroundColor : isEditing ? #colorLiteral(red: 0.7404708266, green: 0.7404883504, blue: 0.7404789329, alpha: 1) : #colorLiteral(red: 0.9984360337, green: 0.893287003, blue: 0.9172400236, alpha: 1)
        ]
        
        usernameField.attributedPlaceholder = NSAttributedString.init(string:   usernameField.placeholder!, attributes: attibutes)
        usernameField.leftView?.tintColor = isEditing ? #colorLiteral(red: 0.7404708266, green: 0.7404883504, blue: 0.7404789329, alpha: 1) : #colorLiteral(red: 0.9646012187, green: 0.9647662044, blue: 0.9645908475, alpha: 1)
        
        usernameField.textColor = isEditing ? #colorLiteral(red: 0.7404708266, green: 0.7404883504, blue: 0.7404789329, alpha: 1) : #colorLiteral(red: 0.9646012187, green: 0.9647662044, blue: 0.9645908475, alpha: 1)
        
        passwordField.attributedPlaceholder = NSAttributedString.init(string: passwordField.placeholder!, attributes: attibutes)
        passwordField.leftView?.tintColor = isEditing ? #colorLiteral(red: 0.7404708266, green: 0.7404883504, blue: 0.7404789329, alpha: 1) : #colorLiteral(red: 0.9646012187, green: 0.9647662044, blue: 0.9645908475, alpha: 1)
        passwordField.textColor = isEditing ? #colorLiteral(red: 0.7404708266, green: 0.7404883504, blue: 0.7404789329, alpha: 1) : #colorLiteral(red: 0.9646012187, green: 0.9647662044, blue: 0.9645908475, alpha: 1)
        
        logo.alpha = isEditing ? 0 : 1
        
        signinButton.setTitleColor(isEditing ? #colorLiteral(red: 0.9646012187, green: 0.9647662044, blue: 0.9645908475, alpha: 1) : #colorLiteral(red: 0.9832398295, green: 0.6316128969, blue: 0.7241895795, alpha: 1), for: .normal)
        signinButton.backgroundColor = isEditing ? #colorLiteral(red: 0.981453836, green: 0.4476600885, blue: 0.6054884791, alpha: 1) : #colorLiteral(red: 0.9984360337, green: 0.893287003, blue: 0.9172400236, alpha: 1)
        
        containerBottomLayout.constant = isEditing ? -600 : -75
    }
    
    private func startAnimation() {
        func animation(duration: CFTimeInterval) -> CABasicAnimation {
            let animation = CABasicAnimation.init(keyPath: "position.x")
            animation.duration = duration
            animation.fromValue = view.bounds.width
            animation.toValue = 0
            animation.fillMode = CAMediaTimingFillMode.forwards
            animation.isRemovedOnCompletion = false
            animation.repeatCount = Float.greatestFiniteMagnitude
            return animation
        }
        
        stackViews[0].layer.add(animation(duration: 20), forKey: "position.x")
        stackViews[1].layer.add(animation(duration: 30), forKey: "position.x")
        
        let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
        rotation.fromValue = Float.pi * 2
        rotation.duration = 10
        rotation.repeatCount = .greatestFiniteMagnitude
        circle.layer.add(rotation, forKey: "rotationAnimation")
    }
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

extension LoginViewController: NibLoadable {}
